#include <stdlib.h>
#include <stdio.h>

#include <iostream>
#include <cstdlib>
#include <cmath>

#include <GL/glut.h>
#include "tinyxml/tinyxml.h"

#include "world.h"
#include "menumanager.h"
#include "menuscreen.h"

#include "globals.h"
#include "tire.h"
#include "car.h"

//global variables
cWorld* myWorld_ptr;
CMenuManager *myMenu_ptr;
int lastx=0;
int lasty=0;
unsigned char Buttons[3] = {0};

int gWindowWidth = SW;
int gWindowHeight = SH;

int gfullscreen = 0;
void drawGrid(void);
void drawRectangle(void);
void drawLine(void);


int gx1 = -30;
int gy1 = 0;

int gx2 = 30;
int gy2 = 30;

int gx3 = 30;
int gy3 = -30;

int gx4 = -30;
int gy4 = -30;

double linex1 = 0;
double liney1 = 0;

double linex2 = -100;
double liney2 = 0;



int gDegreesAlpha = 0;

//	CPiece tmpPiece(LPIECE);

	//forward declaration
	void gl_drawFunc();
	void gl_init(int w, int h);
	void gl_KeypressFunc(unsigned char key, int x, int y);
	void gl_SpecialKeysFunc(int key, int x, int y);

cTire *frontTire_ptr;
cTire *rearRightTire_ptr;


void gl_mouseFunc(int b,int s,int x,int y)
{
	lastx=x;
	lasty=y;
	switch(b)
	{
		case GLUT_LEFT_BUTTON:
			Buttons[0] = ((GLUT_DOWN==s)?1:0);
			break;
		case GLUT_MIDDLE_BUTTON:
			Buttons[2] = ((GLUT_DOWN==s)?1:0);
			break;
		case GLUT_RIGHT_BUTTON:
			Buttons[1] = ((GLUT_DOWN==s)?1:0);
			break;
		default:
			break;		
	}

	glutPostRedisplay();
}


void gl_idleFunc() {
}



//SPACE = 32
//ENTER = 13
void gl_keypressFunc(unsigned char key, int x, int y){
	switch(key) {
		case 27:
			glutPostRedisplay();
			exit(0);
			break;
		case 32: //SPACE
			LOG("space pressed")
			break;

		case 13: //ENTER
			LOG("enter pressed")
			glutPostRedisplay();
			break;
		case 49: //1
		//	if (myWorld_ptr->lineWidth<10) myWorld_ptr->lineWidth++;
			glutPostRedisplay();
			break;
		case 50: //2
		//	if (myWorld_ptr->lineWidth>1) myWorld_ptr->lineWidth--;
			glutPostRedisplay();
			break;
			glutPostRedisplay();
			break;
		case 'f':
			if (!gfullscreen){
				glutFullScreen();
				glutSetCursor(GLUT_CURSOR_FULL_CROSSHAIR);
				gfullscreen=1;
			}
			else {
				glutReshapeWindow(SW, SH);
				glutPositionWindow(177,180);
				gfullscreen=0;
			}
			break;
	}
}

void gl_specialKeysFunc(int key, int x, int y) {
	switch(key){
		case GLUT_KEY_LEFT:
			LOG("left key pressed")
			frontTire_ptr->rotateTire(-2);
			glutPostRedisplay();
			break;
		case GLUT_KEY_RIGHT:
			LOG("right key pressed")
			frontTire_ptr->rotateTire(2);
			double tmplinex2 = linex2 * cosinus(10) - liney2 * sinus(10);
			double tmpliney2 = liney2 * cosinus(10) + linex2 * sinus(10);
//			double tmplinex2 = (double)linex2 * (double)cosinus(36);
//			double tmpliney2 = (double)linex2 * (double)sinus(36);
			linex2 = tmplinex2;
			liney2 = tmpliney2;
//			linex2 = -80.9017
//			liney2 = -47.5528
			glutPostRedisplay();
			break;
		case GLUT_KEY_UP:
			LOG("up key pressed")
			frontTire_ptr->rotateMatrix(10);
			rearRightTire_ptr->rotateMatrix(10);
			glutPostRedisplay();
			break;
		case GLUT_KEY_DOWN:
			LOG("down key pressed")
			frontTire_ptr->rotateMatrix(-10);
			rearRightTire_ptr->rotateMatrix(-10);
			glutPostRedisplay();
			break;
	}
}

void drawRectangle(void) {
	glBegin(GL_LINES);
	 glVertex2i(gx1, gy1);
	 glVertex2i(gx2, gy2);
	 glVertex2i(gx2, gy2);
	 glVertex2i(gx3, gy3);
	 glVertex2i(gx3, gy3);
	 glVertex2i(gx4, gy4);
	 glVertex2i(gx4, gy4);
	 glVertex2i(gx1, gy1);
	glEnd();
}

void drawLine(void) {
	glBegin(GL_LINES);
	 glColor3f(1.0, 0.0, 0.0);
	 glVertex2f(linex1, liney1);
	 glVertex2f(linex2, liney2);
	glEnd();
}

void drawGrid(void) {
	glBegin(GL_LINES);
	 glColor3f(1.0, 1.0, 1.0);
	 //positive x axis
	 glVertex2i(0, 0);
	 glVertex2i(SW/2, 0);

	//arrows positive x axis
	 glVertex2i(SW/2, 0);
	 glVertex2i(SW/2-5, -5);
	 glVertex2i(SW/2, 0);
	 glVertex2i(SW/2-5, +5);
	 
	 //negativ x axis
	 glVertex2i(0, 0);
	 glVertex2i(-SW/2, 0);
	 
	//arrows negative x axis
	 glVertex2i(-SW/2, 0);
	 glVertex2i(-SW/2+5, -5);
	 glVertex2i(-SW/2, 0);
	 glVertex2i(-SW/2+5, +5);
	
	
	
	 //negativ y axis
	 glVertex2i(0, 0);
	 glVertex2i(0, SH/2);

	 //arrows negativ y axis
	 glVertex2i(0, SH/2);
	 glVertex2i(-5, SH/2-5);
	 glVertex2i(0, SH/2);
	 glVertex2i(+5, SH/2-5);
	 
	 //positive y axis
	 glVertex2i(0, 0);
	 glVertex2i(0, -SH/2);

	 //arrows positiv y axis
	 glVertex2i(0, -SH/2);
	 glVertex2i(-5, -SH/2+5);
	 glVertex2i(0, -SH/2);
	 glVertex2i(+5, -SH/2+5);
	glEnd();

	//positive x axis markers
	glBegin(GL_LINES);
	 glColor3f(0.5, 0.5, 0.5);
	for (int i=0; i<SW/2; i+=10) {
	 glVertex2i(i, -5);
	 glVertex2i(i, +5);
	}
	glEnd();
	
	//negative x axis markers
	glBegin(GL_LINES);
	 glColor3f(0.5, 0.5, 0.5);
	for (int i=-10; i>-SW/2; i-=10) {
	 glVertex2i(i, -5);
	 glVertex2i(i, +5);
	}
	glEnd();
	
	//positive y axis markers
	glBegin(GL_LINES);
	 glColor3f(0.5, 0.5, 0.5);
	for (int i=0; i<SH/2; i+=10) {
	 glVertex2i(-5, i);
	 glVertex2i(+5, i);
	}
	glEnd();
	
	//negative y axis markers
	glBegin(GL_LINES);
	 glColor3f(0.5, 0.5, 0.5);
	for (int i=-10; i>-SH/2; i-=10) {
	 glVertex2i(-5, i);
	 glVertex2i(+5, i);
	}
	glEnd();

}

void gl_reshapeFunc(int Width, int Height)
{
	std::cout << "reshape width = " << Width << std::endl;
	std::cout << "reshape height = " << Height << std::endl;
	gWindowWidth=Width;
	gWindowHeight=Height;
    if (Height==0)                              // Prevent A Divide By Zero If The Window Is Too Smal
	Height=1;

	glViewport(0, 0, Width, Height);            // Reset The Current Viewport And Perspective Transfo
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(60.0f,(GLfloat)Width/(GLfloat)Height,0.1f,100.0f);
	glMatrixMode(GL_MODELVIEW);
//	myMenu_ptr->updateWindowSize(Width, Height);
}



void gl_drawFunc()
{
	//3D Draw part START
//	glLineWidth(myWorld_ptr->lineWidth);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glEnable(GL_DEPTH_TEST);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(60.0, (GLfloat)gWindowWidth/(GLfloat)gWindowHeight, 0.0001, 1000.0);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();

	//3D END


	//2D Draw part START
	glDisable(GL_DEPTH_TEST);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glOrtho(0, gWindowWidth, gWindowHeight, 0, -1, 1);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();

//	myMenu_ptr->drawScreenItems(1);

//	glTranslatef(SW/2-200, SH/2-100, 0);
	glTranslatef(SW/2, SH/2, 0);


	drawGrid();
	
	frontTire_ptr->drawTire();
	rearRightTire_ptr->drawTire();

//	drawRectangle();

	drawLine();

/*
	glBegin(GL_QUADS);
	 glColor3f(1.0, 1.0, 1.0);
	 glVertex2i(0, 0);
	 glVertex2i(10, 0);
	 glVertex2i(10, 10);
	 glVertex2i(0, 10);
	glEnd();
*/
	//2D END

	glutSwapBuffers();
}


void gl_init(int w, int h)
{
	glEnable(GL_DEPTH_TEST);
	glEnable(GL_LINE_SMOOTH);
	glDepthFunc(GL_LEQUAL);	
	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
	glHint(GL_LINE_SMOOTH_HINT, GL_DONT_CARE);
	glClearColor(0.0, 0.0, 0.0, 1.0);
	glViewport(0, 0, w, h);
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();

	gluPerspective(60.0, (GLfloat)gWindowWidth/(GLfloat)gWindowHeight, 0.0001, 1000.0);
	//	gluOrtho2D(0, w, 0, h);

	glMatrixMode(GL_MODELVIEW);
}
double sinus(int degrees) {
	return (double)sin((double)degrees/(double)180*(double)3.1415926535);
}

double cosinus(int degrees) {
	return (double)cos((double)degrees/180*3.1415926535);
}

int main(int argc, char **argv)
{
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_RGBA|GLUT_DOUBLE);
	glutInitWindowSize(gWindowWidth, gWindowHeight);
	glutInitWindowPosition(177, 180);
	glutCreateWindow(argv[0]);
	glutDisplayFunc(gl_drawFunc);
	glutKeyboardFunc(gl_keypressFunc);
	glutSpecialFunc(gl_specialKeysFunc);
	glutReshapeFunc(gl_reshapeFunc);

	glutMouseFunc(gl_mouseFunc);
	gl_init(gWindowWidth, gWindowHeight);
	//glutFullScreen();

	cTire rightTire(0,0);
	frontTire_ptr = &rightTire;
	
	cTire rearRightTire(0,100);
	rearRightTire_ptr = &rearRightTire;

	frontTire_ptr->calcVertices();
	rearRightTire_ptr->calcVertices();

	cCar myCar(0,0);

//	cWorld myWorld;
//	myWorld_ptr = &myWorld;

	//create menu
//	CMenuManager myMenu(gWindowWidth, gWindowHeight);
//	myMenu_ptr = &myMenu;

//	myMenu.createMenu("startmenu.xml");
	glutMainLoop();
	return EXIT_SUCCESS;
}

